﻿using System;
using System.Collections.Generic;
using System.Text;
using jade.core.behaviours;
using jade.core;
using MarketSimulator.Utils;
using MarketSimulator.Utils.Attributes;
using jade.lang.acl;
using MarketSimulator.Utils.Communication;

namespace MarketSimulator.UI.Assistant
{
    public class GetBestSellPriceBehavior : OneShotBehaviour
    {
        string ProductName;

        int Quantity;

        public GetBestSellPriceBehavior(string productName, int quantity, AssistantAgent agent) 
            : base(agent)
        {
            ProductName = productName;
            Quantity = quantity;
        }

        public override void action()
        {
            var buyers = YellowPages.FindService(BuyerAttributes.BuyerServiceName, null, this.myAgent, 2000);

            AskBuyersForOffer(ProductName, buyers);

            var prices = ReadOffers();

            (myAgent as AssistantAgent).WriteToChat(Environment.NewLine + "Fund offers: ");
            foreach (var price in prices)
            {
                (myAgent as AssistantAgent).WriteToChat(string.Format("[{0}] : price = {1}; quantity = {2}", price.Key, price.Value.Price, price.Value.Quantity));
            }

            string minPriceSeller = null;
            (myAgent as AssistantAgent).WriteToChat(Environment.NewLine + "Solution: ");
            do
            {
                minPriceSeller = GetMaxPriceBuyer(prices);
                if (minPriceSeller != null)
                {
                    if (prices[minPriceSeller].Quantity > Quantity)
                    {
                        (myAgent as AssistantAgent).WriteToChat(string.Format("Sell {0} to {1} , receiving {2}", Quantity, prices[minPriceSeller].Name, prices[minPriceSeller].Price * Quantity));
                        Quantity = 0;
                    }
                    else
                    {
                        (myAgent as AssistantAgent).WriteToChat(string.Format("Sell {0} to {1}, receiving {2}", prices[minPriceSeller].Quantity, prices[minPriceSeller].Name, prices[minPriceSeller].Price * prices[minPriceSeller].Quantity));
                        Quantity -= prices[minPriceSeller].Quantity;
                        prices.Remove(minPriceSeller);
                    }
                }
            } while (Quantity > 0 && minPriceSeller != null);
        }

        /// <summary>
        /// Ask Prices
        /// </summary>
        /// <param name="product"></param>
        /// <param name="sellers"></param>
        private void AskBuyersForOffer(string product, IList<AID> sellers)
        {
            foreach (var seller in sellers)
            {
                ACLMessage newMessage = new ACLMessage();
                newMessage.addReceiver(seller);
                newMessage.setConversationId(Messages.CONVERSATION_ASK_OFFER);
                newMessage.setContent(product);
                myAgent.send(newMessage);
            }
        }

        /// <summary>
        /// Read Prices
        /// </summary>
        private Dictionary<string, ProductOffer> ReadOffers()
        {
            Dictionary<string, ProductOffer> prices = new Dictionary<string, ProductOffer>();
            ACLMessage receivedMessage;
            MessageTemplate receivePongTemplate = MessageTemplate.MatchConversationId(Messages.CONVERSATION_SAY_OFFER);

            do
            {
                receivedMessage = myAgent.receive(receivePongTemplate);
                if (receivedMessage != null)
                {
                    int newPrice = 0;
                    int newQuantity = 0;
                    string[] parts = receivedMessage.getContent().Split('|');
                    if (int.TryParse(parts[0], out newPrice) && int.TryParse(parts[1], out newQuantity))
                    {
                        var buyOffer = new ProductOffer()
                        {
                            Name = receivedMessage.getSender().getLocalName(),
                            Price = newPrice,
                            Quantity = newQuantity
                        };

                        prices.Add(receivedMessage.getSender().getLocalName(), buyOffer);
                    }
                }

            } while (receivedMessage != null);

            return prices;
        }

        private string GetMaxPriceBuyer(Dictionary<string, ProductOffer> prices)
        {
            int maxPrice = -1;
            string seller = null;

            foreach (var element in prices)
            {
                if (element.Value.Price > maxPrice || maxPrice < 0)
                {
                    maxPrice = element.Value.Price;
                    seller = element.Key;
                }
            }

            return seller;
        }
    }
}
